# -*- coding: utf-8 -*-
"""
    归档逻辑
"""
import uuid
import itertools


class ArchiveLogic:
    def __init__(self, redis_client, face_acvs_level_limit, acvs_acvs_level_limit):
        self.redis_client = redis_client
        self.face_acvs_level_limit = face_acvs_level_limit
        self.acvs_acvs_level_limit = acvs_acvs_level_limit

    @staticmethod
    def is_in_acvs(hit_count, hit_acvs_len):
        if hit_acvs_len < 5:
            return True
        elif hit_count >= 2:
            return True
        return False

    @staticmethod
    def blur_angle(hit_face_img):
        if (abs(float(hit_face_img['x'])) > 40) or (abs(float(hit_face_img['y'])) > 40) or (
                abs(float(hit_face_img['z'])) > 40) or int(hit_face_img['detectCount']) >= 2:
            return False
        else:
            return True

    def redis_insacvs(self, face_id, acvs_id, count):
        # 判断 脸档是否拆掉
        del_list = self.redis_client.rdb_face_acvs(face_id)
        if acvs_id in del_list:
            return None

        self.redis_client.rdb_zadd_face_acvs(face_id, acvs_id, count)
        self.redis_client.rdb_zadd_acvs_face(acvs_id, face_id, count)
        self.redis_client.rdb_queue_push_log_ins_acvs(face_id, acvs_id, count)

    # 其他的空档进档
    def insert_other_empty(self, other_front_empty_list, face_score, acvs_id, other_side_face_empty_list):
        for other_id in other_front_empty_list:
            other_score = 1
            other_has = self.redis_client.rdb_has_face_acvs(other_id, acvs_id)
            if not other_has:
                face_score += other_score
                self.redis_insacvs(other_id, acvs_id, other_score + 200000)

            if other_has:
                other_src_score = int(self.redis_client.rdb_get_face_acvs(other_id, acvs_id))
                if other_src_score > 300000:
                    face_score += other_score
                    self.redis_insacvs(other_id, acvs_id, other_score + 200000)

                elif 200000 < other_src_score:
                    face_score += other_score
                    self.redis_insacvs(other_id, acvs_id, other_src_score + 1)

        for aother_side_id in other_side_face_empty_list:
            other_side_score = 1
            other_side_has = self.redis_client.rdb_has_face_acvs(aother_side_id, acvs_id)
            if not other_side_has:
                face_score += other_side_score
                self.redis_insacvs(aother_side_id, acvs_id, other_side_score + 1100000)

            if other_side_has:
                other_side_src_score = int(self.redis_client.rdb_get_face_acvs(aother_side_id, acvs_id)) + 1
                face_score += other_side_score

                self.redis_insacvs(aother_side_id, acvs_id, other_side_src_score)

        return face_score

    # 多人建档
    def insert_multiplayer(self, faceid, acvs_id, empty_list, other_front_empty_list, other_side_face_empty_list,
                           face_acvs_has):
        face_score = 0
        for hit_faceid in empty_list:
            hit_facescore = 1
            face_score += hit_facescore
            # 档里可能有 但级别低 新建的档 都没有 --不用判断有无
            self.redis_insacvs(hit_faceid, acvs_id, hit_facescore + 100000)

        face_score = self.insert_other_empty(other_front_empty_list, face_score, acvs_id, other_side_face_empty_list)
        if not face_acvs_has:
            self.redis_insacvs(faceid, acvs_id, face_score + 100000)

        else:
            count = int(self.redis_client.rdb_get_acvs_face(acvs_id, faceid))
            self.redis_insacvs(faceid, acvs_id, face_score + count)

    # 进他人档
    def insert_others(self, faceid, acvs_id, empty_list, level_dic1, other_front_empty_list,
                      other_side_face_empty_list):
        face_score = 0
        for hit_faceid in empty_list:
            hit_facescore = 1
            # 档里可能有 但级别低 需要判断(一级空挡列表)
            hit_face_has = self.redis_client.rdb_has_face_acvs(hit_faceid, acvs_id)
            if hit_face_has:
                score = int(self.redis_client.rdb_get_face_acvs(hit_faceid, acvs_id))
                level = int(str(score)[:-5] + '00000')
                # 叠加了贡献度
                tar_score = score - level
            else:
                tar_score = 0

            acvs_count = self.redis_client.rdb_get_acvs_len1(acvs_id)
            if acvs_count < 5:
                face_score += hit_facescore

                self.redis_insacvs(hit_faceid, acvs_id, hit_facescore + tar_score + 100000)

            else:
                # 入二级档 可能已有二级档 判断
                if hit_face_has:
                    score = int(self.redis_client.rdb_get_face_acvs(hit_faceid, acvs_id))
                    if score > 300000:
                        self.redis_insacvs(hit_faceid, acvs_id, hit_facescore + tar_score + 200000)

                    if 200000 < score < 300000:
                        self.redis_insacvs(hit_faceid, acvs_id, score + 1)

                if not hit_face_has:
                    self.redis_insacvs(hit_faceid, acvs_id, hit_facescore + 200000)

        # 升级命中档内的数量
        for hit_acvs_face in level_dic1['1']:
            if hit_acvs_face[0] == acvs_id:
                hit_face_score = 1
                # 档里肯定有
                face_score += hit_face_score
                countt = int(self.redis_client.rdb_get_face_acvs(hit_acvs_face[1], acvs_id)) + hit_face_score

                self.redis_insacvs(hit_acvs_face[1], acvs_id, countt)
        # 其他空档的正脸和侧脸
        face_score = self.insert_other_empty(other_front_empty_list, face_score, acvs_id, other_side_face_empty_list)

        # 档里没有 现在档里可能有(多个盒子)
        face_has = self.redis_client.rdb_has_face_acvs(faceid, acvs_id)
        if not face_has:
            self.redis_insacvs(faceid, acvs_id, face_score + 100000)

        if face_has:
            score_face = int(self.redis_client.rdb_get_face_acvs(faceid, acvs_id))
            level_face = int(str(score_face)[:-5] + '00000')
            # 贡献度叠加
            tar_score_face = score_face - level_face

            if 100000 < score_face < 200000:
                self.redis_insacvs(faceid, acvs_id, face_score + score_face)

            else:
                self.redis_insacvs(faceid, acvs_id, face_score + tar_score_face + 100000)

    def empty_insert(self, faceid, level_dic, acvs_id, new_level, level_zdd, similarity, other_front_empty_list,
                     other_side_face_empty_list):
        count = 0
        empty_level = new_level + level_zdd
        if empty_level > self.face_acvs_level_limit:
            return count

        for hitface in other_front_empty_list:
            has = self.redis_client.rdb_has_acvs_face(acvs_id, hitface)
            if not has:
                count += 1

                self.redis_insacvs(hitface, acvs_id, new_level + level_zdd + 1)

        for side_hitface in other_side_face_empty_list:
            side_has = self.redis_client.rdb_has_acvs_face(acvs_id, side_hitface)
            if not side_has:
                count += 1

                self.redis_insacvs(side_hitface, acvs_id, 1100000 + 1)

        return count

    # 进档的其他级别
    def insert_level(self, face_id, level_dic, level_zdd, similarity, acvs_dic, other_front_empty_list,
                     other_side_face_empty_list):
        for key in level_dic:
            if key == '0':
                continue
            else:
                self.key_level(key, face_id, level_dic, level_zdd, similarity, acvs_dic, other_front_empty_list,
                               other_side_face_empty_list)

    @staticmethod
    def acvsdic(new_level, acvs_id, acvs_dic):
        level = str(new_level)[:-5]
        if level in acvs_dic:
            acvs_dic[level].append(acvs_id)
        if level not in acvs_dic:
            acvs_dic[level] = []
            acvs_dic[level].append(acvs_id)

    def key_level(self, key, face_id, level_dic, level_zdd, similarity, acvs_dic, other_front_empty_list,
                  other_side_face_empty_list):
        level = int(key + '00000')  # 原本的级别
        new_level = level + level_zdd
        if new_level > self.face_acvs_level_limit:
            return
        for acvs_face in level_dic[key]:
            acvs_id = acvs_face[0]
            hit_face_id = acvs_face[1]
            face_has = self.redis_client.rdb_has_face_acvs(face_id, acvs_id)
            if not face_has:
                self.acvsdic(new_level, acvs_id, acvs_dic)
                count = self.empty_insert(face_id, level_dic, acvs_id, new_level, level_zdd, similarity,
                                          other_front_empty_list, other_side_face_empty_list)

                self.redis_insacvs(face_id, acvs_id, new_level + count + 1)

                # 升级 hitface
                countt = int(self.redis_client.rdb_get_acvs_face(acvs_id, hit_face_id)) + 1

                self.redis_insacvs(hit_face_id, acvs_id, countt)

            if face_has:
                face_score = int(self.redis_client.rdb_get_face_acvs(face_id, acvs_id))
                if face_score < new_level + 100000:
                    self.acvsdic(new_level, acvs_id, acvs_dic)
                    count = self.empty_insert(face_id, level_dic, acvs_id, new_level, level_zdd, similarity,
                                              other_front_empty_list, other_side_face_empty_list)

                    countt = int(self.redis_client.rdb_get_acvs_face(acvs_id, face_id)) + count + 1

                    self.redis_insacvs(face_id, acvs_id, countt)

                    # 升级 hitface
                    counttt = int(self.redis_client.rdb_get_acvs_face(acvs_id, hit_face_id)) + 1

                    self.redis_insacvs(hit_face_id, acvs_id, counttt)

                if face_score > new_level + 100000:
                    level_face = int(str(face_score)[:-5] + '00000')
                    tar_score_face = face_score - level_face

                    self.acvsdic(new_level, acvs_id, acvs_dic)
                    count = self.empty_insert(face_id, level_dic, acvs_id, new_level, level_zdd, similarity,
                                              other_front_empty_list, other_side_face_empty_list)

                    self.redis_insacvs(face_id, acvs_id, tar_score_face + new_level + count + 1)

                    # 升级 hitface
                    counttt = int(self.redis_client.rdb_get_acvs_face(acvs_id, hit_face_id)) + 1

                    self.redis_insacvs(hit_face_id, acvs_id, counttt)

    # 特殊的98正脸去掉一级档
    def insert_level1(self, face_id, level_dic, level_zdd, simliraty, acvs_dic, other_front_empty_list,
                      other_side_face_empty_list):
        for key in level_dic:
            if key == '0' or key == '1':
                continue
            else:
                self.key_level(key, face_id, level_dic, level_zdd, simliraty, acvs_dic, other_front_empty_list,
                               other_side_face_empty_list)

    # face侧脸
    def insert_side_face(self, face_id, level_dic, acvs_dic):
        for key in level_dic:
            for acvs_face in level_dic[key]:
                acvs_id = acvs_face[0]
                hit_face_id = acvs_face[1]
                face_has = self.redis_client.rdb_has_face_acvs(face_id, acvs_id)
                if not face_has:
                    self.acvsdic(1100000, acvs_id, acvs_dic)
                    self.redis_insacvs(face_id, acvs_id, 1 + 1100000)

                if face_has:
                    self.acvsdic(1100000, acvs_id, acvs_dic)
                    face_score = int(self.redis_client.rdb_get_face_acvs(face_id, acvs_id)) + 1
                    self.redis_insacvs(face_id, acvs_id, face_score)

                # 升级 hitface
                counttt = int(self.redis_client.rdb_get_acvs_face(acvs_id, hit_face_id)) + 1
                self.redis_insacvs(hit_face_id, acvs_id, counttt)

    # 为了建立档档关
    @staticmethod
    def acvs_dic_one(acvs_dic, acvs_id):
        if '1' in acvs_dic:
            acvs_dic['1'].append(acvs_id)
        if '1' not in acvs_dic:
            acvs_dic['1'] = []
            acvs_dic['1'].append(acvs_id)

    # 入口
    def face_acvs_level(self, faceid, facedet, level_dic1, level_dic2, level_dic3, level_dic4, hit_card_list,
                        ovo_not_satisfied_list):
        # acvs_dic
        acvs_dic = {}
        # 命中一级空档的数量
        empty_list = []
        # 命中一级档人脸list
        has_acvs_face_list = []
        if "1" in level_dic1.keys():
            for lis in level_dic1["1"]:
                has_acvs_face_list.append(lis[1])

        for keyy in level_dic1.keys():
            if keyy == '1':
                continue
            elif keyy == '0':
                for liss in level_dic1[keyy]:
                    if liss not in empty_list:
                        empty_list.append(liss)
            else:
                for lisss in level_dic1[keyy]:
                    if (lisss[1] not in has_acvs_face_list) and (lisss[1] not in empty_list):
                        empty_list.append(lisss[1])

        # 可入一级档列表
        in_acvs_list = []
        # 不可入档列表（在可进档列表里）
        not_in_acvs_list = []
        # 不进档列表对应的hitfaceid
        not_in_acvs_hitlist = []

        # 命中98正
        if '1' in level_dic1.keys():
            # 命中一档内列表
            acvs_face_list1 = level_dic1['1']
            # 统计一级档案map
            acvs_map1 = {}
            for acvs_face in acvs_face_list1:
                acvs_id = acvs_face[0]
                if acvs_id not in acvs_map1:
                    acvs_map1[acvs_id] = 0
                acvs_map1[acvs_id] += 1
            # 统计档案列表 数量大到小
            acvs_list1 = sorted(acvs_map1.items(), key=lambda d: d[1], reverse=True)

            for hit_acvs_count in acvs_list1:
                hit_acvs = hit_acvs_count[0]
                hit_count = hit_acvs_count[1]
                # 档内 一级 脸的数量
                hit_acvs_len = self.redis_client.rdb_get_acvs_len1(hit_acvs)
                if self.is_in_acvs(hit_count, hit_acvs_len):
                    in_acvs_list.append(hit_acvs_count)
                # 不满足条件 入二级档
                if not self.is_in_acvs(hit_count, hit_acvs_len):
                    not_in_acvs_list.append(hit_acvs)

            for keyyy in level_dic1['1']:
                if keyyy[0] in not_in_acvs_list:
                    not_in_acvs_hitlist.append((keyyy[0], keyyy[1]))
        # 另外的正脸和侧脸 空档列表
        other_front_empty_list = []
        other_side_face_empty_list = []

        other_side_face_empty_list = other_side_face_empty_list + level_dic2[
            '0'] if '0' in level_dic2 else other_side_face_empty_list
        other_front_empty_list = other_front_empty_list + level_dic3[
            '0'] if '0' in level_dic3 else other_front_empty_list
        other_side_face_empty_list = other_side_face_empty_list + level_dic4[
            '0'] if '0' in level_dic4 else other_side_face_empty_list

        if facedet:
            # 入他人档
            if len(in_acvs_list) > 0:
                # 先判断自己是不是建档face 有且不在列表里 加入进档dic
                face_acvs_has = self.redis_client.rdb_get_face_new_acvs(faceid)
                if face_acvs_has and (face_acvs_has not in in_acvs_list):
                    self.acvs_dic_one(acvs_dic, face_acvs_has)

                for acvs_count in in_acvs_list:
                    acvs_id = acvs_count[0]
                    self.acvs_dic_one(acvs_dic, acvs_id)
                    self.insert_others(faceid, acvs_id, empty_list, level_dic1, other_front_empty_list,
                                       other_side_face_empty_list)

            # 多人建档
            elif len(empty_list) > 0:
                # 先判断自己是不是建档face 有则将自己的档当作新建档
                face_acvs_has = self.redis_client.rdb_get_face_new_acvs(faceid)
                if not face_acvs_has:
                    # 传入指定人像库，faceid不变 待增加
                    acvs_id = str(uuid.uuid1())
                    self.redis_client.rdb_queue_push_log_add_acvs(acvs_id, faceid)
                    self.redis_client.rdb_add_acvs(faceid, acvs_id)
                else:
                    acvs_id = face_acvs_has

                # 为了建立档档关系
                self.acvs_dic_one(acvs_dic, acvs_id)

                self.insert_multiplayer(faceid, acvs_id, empty_list, other_front_empty_list, other_side_face_empty_list,
                                        face_acvs_has)

            # 进2级档
            if len(not_in_acvs_hitlist) > 0:
                for not_hitacvs_count in not_in_acvs_hitlist:
                    not_acvsid = not_hitacvs_count[0]
                    not_hitface = not_hitacvs_count[1]

                    # 判断有没有一级档
                    face_src_has = self.redis_client.rdb_has_face_acvs(faceid, not_acvsid)
                    if face_src_has:
                        face_src_score = int(self.redis_client.rdb_get_face_acvs(faceid, not_acvsid))
                        if 100000 < face_src_score < 200000:
                            continue
                        if 200000 < face_src_score < 300000:
                            self.redis_insacvs(faceid, not_acvsid, face_src_score + 1)

                        if 300000 < face_src_score:
                            face_level = int(str(face_src_score)[:-5] + '00000')
                            new_score = face_src_score - face_level

                            self.redis_insacvs(faceid, not_acvsid, 1 + 200000 + new_score)

                    if not face_src_has:
                        self.redis_insacvs(faceid, not_acvsid, 1 + 200000)

                    if '2' in acvs_dic:
                        acvs_dic['2'].append(not_acvsid)
                    if '2' not in acvs_dic:
                        acvs_dic['2'] = []
                        acvs_dic['2'].append(not_acvsid)

                    # 升级hitface
                    countt = int(self.redis_client.rdb_get_acvs_face(not_acvsid, not_hitface)) + 1

                    self.redis_insacvs(not_hitface, not_acvsid, countt)

            if '0' in level_dic1:
                other_front_empty_list = other_front_empty_list + level_dic1['0']

            # 目的 进入他人档
            self.insert_level1(faceid, level_dic1, 100000, 98, acvs_dic, other_front_empty_list,
                               other_side_face_empty_list)
            self.insert_level(faceid, level_dic2, 100000, 98, acvs_dic, other_front_empty_list,
                              other_side_face_empty_list)
            self.insert_level(faceid, level_dic3, 100000, 97, acvs_dic, other_front_empty_list,
                              other_side_face_empty_list)
            self.insert_level(faceid, level_dic4, 100000, 97, acvs_dic, other_front_empty_list,
                              other_side_face_empty_list)

        if not facedet:
            # 侧脸不处理空档
            self.insert_side_face(faceid, level_dic1, acvs_dic)
            self.insert_side_face(faceid, level_dic3, acvs_dic)

        # acvs_acvs关系 db2
        # print(acvs_dic)

        self.acvs_acvs(facedet, faceid, acvs_dic, hit_card_list, ovo_not_satisfied_list)

    def redis_card_acvs(self, cardid, acvsid, count, faceid):
        self.redis_client.rdb_queue_push_log_add_card(cardid, acvsid, count, faceid)
        self.redis_client.rdb_zadd_card_arch(cardid, acvsid, count)
        self.redis_client.rdb_zadd_acvs_card(acvsid, cardid, count)

    def acvs_card(self, faceid, all_acvlis, acvslevel_dic, hit_card_list):
        for acvsid in all_acvlis:
            level = acvslevel_dic[acvsid]
            levellong = int(str(level) + '00000')
            for card_score in hit_card_list:
                cardid = card_score[0]
                similarity = card_score[1]
                # card_acvs db6
                card_acvshas = self.redis_client.rdb_has_card_arch(cardid, acvsid)
                if card_acvshas:
                    # 删了一个log
                    score = int(self.redis_client.rdb_get_card_score(cardid, acvsid))
                    if score > levellong + 100000:
                        # 升级档卡
                        self.redis_card_acvs(cardid, acvsid, levellong + similarity, faceid)

                    if levellong < score < levellong + 100000:
                        # 只升级相似度
                        sim = score - levellong
                        if similarity > sim:
                            sim_new = levellong + similarity
                            self.redis_card_acvs(cardid, acvsid, sim_new, faceid)
                        else:
                            self.redis_client.rdb_queue_push_log_add_card(cardid, acvsid, levellong + similarity,
                                                                          faceid)

                    if score < levellong:
                        self.redis_client.rdb_queue_push_log_add_card(cardid, acvsid,
                                                                      score - int(str(score)[-2:] + similarity),
                                                                      faceid)
                if not card_acvshas:
                    card_img = self.redis_client.rdb_get_face(cardid)
                    if card_img.get("name"):
                        self.redis_client.rdb_queue_log_hide_card(acvsid)
                    self.redis_card_acvs(cardid, acvsid, levellong + similarity, faceid)

    def ten_level(self, faceid, all_acvlis, ovo_not_satisfied_list):
        for ovo_not_face_id in ovo_not_satisfied_list:
            ovo_acvs_id_list = self.redis_client.rdb_get_ovo_face_acvs(ovo_not_face_id, start=0, end=-1)
            for acvs_id in all_acvlis:
                if acvs_id in ovo_acvs_id_list:
                    continue
                else:
                    if len(ovo_acvs_id_list) == 0:
                        self.redis_insacvs(ovo_not_face_id, acvs_id, 1 + 1000000)

                        # 升级hitface
                        countt = int(self.redis_client.rdb_get_acvs_face(acvs_id, faceid)) + 1

                        self.redis_insacvs(faceid, acvs_id, countt)

                    else:
                        for ovo_acvs_id in ovo_acvs_id_list:
                            self.redis_insacvs(faceid, ovo_acvs_id, 1 + 1000000)

                            # 升级hitface
                            countt = int(self.redis_client.rdb_get_acvs_face(ovo_acvs_id, ovo_not_face_id)) + 1

                            self.redis_insacvs(ovo_not_face_id, ovo_acvs_id, countt)

    def acvs_acvs(self, facedet, faceid, acvsdic, hit_card_list, ovo_not_satisfied_list):
        # 统计所有的档  对档进行筛选
        all_acvlis = []
        acvslevel_dic = {}
        for key in acvsdic:
            for acvsid in acvsdic[key]:
                if acvsid in acvslevel_dic:
                    level = acvslevel_dic[acvsid]
                    if int(key) < level:
                        acvslevel_dic[acvsid] = int(key)
                if acvsid not in acvslevel_dic:
                    acvslevel_dic[acvsid] = int(key)

                if acvsid not in all_acvlis:
                    all_acvlis.append(acvsid)
        # 放10级
        if len(ovo_not_satisfied_list) > 0:
            self.ten_level(faceid, all_acvlis, ovo_not_satisfied_list)

        # 建立档证
        self.acvs_card(faceid, all_acvlis, acvslevel_dic, hit_card_list)

        if len(all_acvlis) == 0:
            self.redis_client.rdb_queue_push_log_unacvs(faceid)

        # 建立关系前提
        if facedet and len(all_acvlis) > 0:
            self.permutations_acvs(all_acvlis, acvslevel_dic)

    def redis_acvs_acvs(self, acvs1, acvs2, count):
        del_list = self.redis_client.rdb_acvs_acvs(acvs1)
        if acvs2 in del_list:
            return None
        self.redis_client.rdb_zadd_acvs_acvs(acvs1, acvs2, count)
        self.redis_client.rdb_zadd_acvs_acvs(acvs2, acvs1, count)
        self.redis_client.rdb_queue_push_log_acvs_acvs(acvs1, acvs2, count)

    def permutations_acvs(self, all_acvlis, acvslevel_dic):
        # 组合
        for acvs1_2 in itertools.combinations(all_acvlis, 2):
            acvs1 = acvs1_2[0]
            level1 = acvslevel_dic[acvs1]
            acvs2 = acvs1_2[1]
            level2 = acvslevel_dic[acvs2]
            level3 = str(level1 * level2)
            level = int(level3 + '00000')

            if level > self.acvs_acvs_level_limit:
                return

            # 建立档档 相加
            acvs_has = self.redis_client.rdb_has_acvs_acvs(acvs1, acvs2)
            if acvs_has:
                score = self.redis_client.rdb_get_acvs_acvs(acvs1, acvs2)
                level_src = int(str(score)[:-5] + '00000')
                tar_score = score - level_src

                if score > level + 100000:
                    self.redis_acvs_acvs(acvs1, acvs2, level + tar_score + 1)

                if score < level + 100000:
                    self.redis_client.rdb_add_acvs_acvs(acvs1, acvs2)
                    self.redis_client.rdb_add_acvs_acvs(acvs2, acvs1)

                    count = self.redis_client.rdb_get_acvs_acvs(acvs1, acvs2)
                    self.redis_client.rdb_queue_push_log_acvs_acvs(acvs1, acvs2, count)

            if not acvs_has:
                self.redis_acvs_acvs(acvs1, acvs2, level + 1)
